#include <stdio.h>
#include <stdint.h>
#include <Windows.h>
#include <process.h>
#include <assert.h>
#include <TCHAR.h>
#include "CH58x_common.h"
#include "simu_mcu582.h"

void UART0_DefInit() { ; }
void UART1_DefInit() { ; }
void UART2_DefInit() { ; }
void UART0_BaudRateCfg(int x) { ; }
void UART1_BaudRateCfg(int x) { ; }
void UART2_BaudRateCfg(int x) { ; }
void UART0_ByteTrigCfg(int x) { ; }
void UART1_ByteTrigCfg(int x) { ; }
void UART2_ByteTrigCfg(int x) { ; }
void UART0_INTCfg(int x) { ; }
void UART1_INTCfg(int x) { ; }
void UART2_INTCfg(int x) { ; }

ZqSimuUartHandle zq_simu_uart_handle[4] = { 0 };

void UartLock(uint8_t port)
{
    WaitForSingleObject(zq_simu_uart_handle[port].mutex, -1);
}
void UartUnlock(uint8_t port)
{
    ReleaseMutex(zq_simu_uart_handle[port].mutex);
}

#define UART_BUF_SIZE 2048
static void SimuUartThreadFunc(void * port_num)
{
    uint8_t port = (uint8_t)port_num;
    uint32_t len = 0;
    ZqSimuUartHandle* simu_uart = &(zq_simu_uart_handle[port]);
    HANDLE h = (simu_uart->uart) ? simu_uart->uart : simu_uart->pipe_read; // 使用串口还是管道模拟
    uint8_t buf[UART_BUF_SIZE];
    while (1) {
        BOOL b = ReadFile(h, buf, UART_BUF_SIZE, &len, NULL);
        if (b && 0 < len) {//读成功并且数据大小大于0
            UartLock(port);
            if (len > (simu_uart->rx_buf_size - simu_uart->rx_buf_pos))
                len = simu_uart->rx_buf_size - simu_uart->rx_buf_pos;
            memcpy(simu_uart->rx_buf + simu_uart->rx_buf_pos, buf, len);
            simu_uart->rx_buf_pos += len;
            UartUnlock(port);
        }
    }
}
void SimuUartInit(uint8_t port, int baudrate, uint8_t* rx_buf, uint16_t rx_buf_size)
{
    DCB dcb;
    COMMTIMEOUTS CommTimeouts;
    ZqSimuUartHandle* simu_uart = &(zq_simu_uart_handle[port]);
    if (simu_uart->uart_port_str == NULL && simu_uart->pipe_read == NULL) return; // 串口未配置
    if (simu_uart->rx_thread != NULL) return; // 已经被占用
    
    simu_uart->mutex = CreateMutex(NULL, FALSE, NULL);
    simu_uart->rx_buf = rx_buf;
    simu_uart->rx_buf_size = rx_buf_size;
    simu_uart->rx_buf_pos = 0;

    if(simu_uart->pipe_read) { // 使用管道模拟
        // 启动模拟接受线程
        simu_uart->rx_thread = _beginthread(SimuUartThreadFunc, 0, (void *)port);
        assert(INVALID_HANDLE_VALUE != simu_uart->rx_thread);
        return;
    }

    int wcom_port_len = strlen(simu_uart->uart_port_str) + 1;
    assert(wcom_port_len < 64);
    wchar_t wcom_port[32] = { 0 };
    mbstowcs(wcom_port, simu_uart->uart_port_str, wcom_port_len);
    //使用串口模拟, 打开串口
    simu_uart->uart = CreateFile(
        wcom_port,                      //串口名称
        GENERIC_READ | GENERIC_WRITE,	//可读、可写   				 
        0,            // No Sharing                               
        NULL,         // No Security                              
        OPEN_EXISTING,// Open existing port only                     
        FILE_ATTRIBUTE_NORMAL,            // Non Overlapped I/O                           
        NULL);        // Null for Comm Devices
    if (INVALID_HANDLE_VALUE == simu_uart->uart) {
        DWORD err = GetLastError();
        return;
    }

    // 设置读写缓存大小
    if (!SetupComm(simu_uart->uart, simu_uart->rx_buf_size, simu_uart->rx_buf_size)) assert(0);

    //设定读写超时
    //CommTimeouts.ReadIntervalTimeout = 1;//读间隔超时
    CommTimeouts.ReadIntervalTimeout = MAXDWORD;//读间隔超时
    CommTimeouts.ReadTotalTimeoutMultiplier = 0;//读时间系数
    CommTimeouts.ReadTotalTimeoutConstant = 1;//读时间常量
    CommTimeouts.WriteTotalTimeoutMultiplier = 0;//写时间系数
    CommTimeouts.WriteTotalTimeoutConstant = 10;//写时间常量
    if (!SetCommTimeouts(simu_uart->uart, &CommTimeouts)) assert(0);

    //设置串口状态属性
    GetCommState(simu_uart->uart, &dcb);//获取当前
    dcb.BaudRate = baudrate; //波特率
    dcb.ByteSize = 8; //每个字节有效位数
    dcb.Parity = NOPARITY; //无奇偶校验位
    dcb.StopBits = ONESTOPBIT; //一个停止位
    if (!SetCommState(simu_uart->uart, &dcb)) assert(0);

    // 启动模拟接受线程
    simu_uart->rx_thread = _beginthread(SimuUartThreadFunc, 0, (void*)port);
    assert(INVALID_HANDLE_VALUE != simu_uart->rx_thread);

    return;
}
void SimuUartClose(uint8_t port)
{
    ZqSimuUartHandle* simu_uart = &(zq_simu_uart_handle[port]);
    if (simu_uart->uart)
        CloseHandle(simu_uart->uart);
    if (simu_uart->rx_thread) {
        TerminateThread(simu_uart->rx_thread, 0);
        CloseHandle(simu_uart->rx_thread);
    }
    simu_uart->rx_thread = simu_uart->uart = NULL;
}
void SimuUartSend(uint8_t port, uint8_t* buf, uint16_t len)
{
    unsigned int ret = 0;
    HANDLE h = (zq_simu_uart_handle[port].uart) ? zq_simu_uart_handle[port].uart : zq_simu_uart_handle[port].pipe_write; // 使用串口还是管道模拟
    WriteFile(h, buf, len, &ret, NULL);
}

